<template>
  <el-card
    style="width: 100%; box-shadow: none; border: none"
    :body-style="{ paddingBottom: 0 }"
    v-if="keys.length"
    ><el-form
      ref="form"
      :model="data"
      :label-position="labelPosition"
      :label-width="labelWidth"
      :label-suffix="labelSuffix"
      :disabled="disabled"
      :require-asterisk-position="requirePosition"
    >
      <el-row :gutter="props?.ui?.gutter || 20">
        <el-col
          v-for="(key, i) in !isEdit ? searchKeys : keys"
          :key="i"
          :span="isEdit ? getGrid(key).span : searchSpan"
          v-acl="properties[key]?.ui?.acl || ''"
        >
          <lc-sf-item
            :field="key"
            :keyPath="sf.getKey(key, keyPath)"
            :service="getService(key)"
            v-model:data="data[key]"
          />
        </el-col>
        <el-col v-if="!isEdit" :span="searchSpan">
          <div class="flex">
            <el-button
              type="primary"
              :icon="Search"
              :disabled="!sf.vaild"
              @click="emits('submit', toRaw(data))"
              >查询</el-button
            >
            <el-button type="primary" :icon="Refresh" @click="reset()"
              >重置</el-button
            >
            <el-button
              v-if="keys.length > searchSpan + 1"
              type="primary"
              @click="showMore = !showMore"
              :icon="showMore ? ArrowDown : ArrowUp"
              >更多</el-button
            >
          </div>
        </el-col>
        <el-col
          v-for="(key, i) in otherKeys"
          :key="i"
          :span="isEdit ? getGrid(key).span : 4"
          v-acl="properties[key]?.ui?.acl || ''"
        >
          <lc-sf-item
            :field="key"
            :keyPath="sf.getKey(key, keyPath)"
            :service="getService(key)"
            v-model:data="data[key]"
          />
        </el-col>
      </el-row> </el-form
  ></el-card>
</template>

<script lang="ts" setup name="lc-sf">
import { Refresh, Search, ArrowDown, ArrowUp } from "@element-plus/icons-vue";
import { NzSafeAny, TFormOption } from "./type";
import { ref, watch, inject, provide, toRaw, computed } from "vue";
import type { FormInstance } from "element-plus";
import { SFGridSchema } from "./interface";
import LcSfItem from "./sf-item/sf-item.vue";
import { SFItemService } from "./sf-item/sf-item.service";
import { SFService } from "./sf.service";
import { acl } from "@/directives";
defineOptions({
  directives: { acl }
});
/** 初始化父传子的数据*/
const props = withDefaults(defineProps<TFormOption>(), {
  data: (props: TFormOption) => props.data || {},
  labelPosition: (props: TFormOption) => props.labelPosition || "right",
  labelWidth: (props: TFormOption) => props.labelWidth || 80,
  labelSuffix: (props: TFormOption) => props.labelSuffix || "",
  requirePosition: (props: TFormOption) => props.requirePosition || "left",
  disabled: (props: TFormOption) => props.disabled || false,
  schema: (props: TFormOption) => props.schema || {},
  keyPath: (props: TFormOption) => props.keyPath || "",
  moda: (props: TFormOption) => props.moda || "edit",
  searchSpan: (props: TFormOption) => props.searchSpan,
  ui: (props: TFormOption) => props.ui || { spanLabel: 80, span: 24 }
});
const emits = defineEmits(["formChange", "submit"]);
const form = ref<FormInstance>();
const showMore = ref(false);
const searchSpan = computed(() => {
  return props.searchSpan || 4;
});
/** 是否是编辑模式 */
const isEdit = props.moda !== "search";
/** 变化部分参数为响应式*/
const schema = toRaw(props.schema);
/** 当前字段属性 */
const properties = schema?.properties || {};
/** 所有字段集合 */

const keys = Object.keys(schema?.properties || {});
const searchKeys = keys.slice(0, searchSpan.value + 1);
const otherKeys = computed(() => {
  return showMore.value && !isEdit ? keys.slice(searchSpan.value + 1) : [];
});
const reset = () => {
  form.value?.resetFields();
  emits("submit", {});
};
/** 必填字段集合 */
const required = schema?.required || [];
/** 当前字段是否必填*/
const isRequired = (key: string) => {
  return (required || []).includes(key);
};
const isOk = (res: NzSafeAny) => {
  return ![undefined, "", null].includes(res);
};
/** 所有字段对应得值 */
const data = ref<Record<string, NzSafeAny>>(props.data);
const setValue = () => {
  keys.forEach(k => {
    const ui = properties?.[k]?.ui;
    const preFormat = ui.preFormat;
    const dft =
      ui.widget === "array" ? [] : ui.widget === "object" ? {} : undefined;

    const val = isOk(props?.data?.[k])
      ? props?.data?.[k]
      : isOk(properties?.[k]?.default)
      ? properties?.[k]?.default
      : dft;

    data.value[k] = preFormat ? preFormat(val) : val;
  });
};
setValue();
const sf = inject<SFService>("sf-service", null) ?? new SFService(data.value);
provide("sf-service", sf);
const getService = (key: string) => {
  const read = properties?.[key].readonly;
  properties[key].readonly =
    typeof read === "function" ? read(toRaw(data.value)) : read;

  const service = new SFItemService(toRaw(properties?.[key]), isRequired(key));
  sf.setItem(service, sf.getKey(key, props.keyPath));
  return service;
};
const getGrid = (key: string): SFGridSchema => {
  const dGrid = {
    spanLabel: props?.ui?.spanLabel || 80,
    span: props?.ui?.span || 24
  } as SFGridSchema;
  const grid = properties[key]?.ui?.grid || {};
  return Object.assign(dGrid, grid);
};

watch(data.value, () => {
  emits("formChange", toRaw(data.value));
});
const vaild = computed(() => {
  if (!form.value) {
    return false;
  }
  return sf.vaild;
});
defineExpose({
  service: sf,
  reset: setValue,
  vaild,
  form
});
</script>

<style></style>
./interfaces ./types
